#!/usr/bin/perl
#
# Please refer to the Plain Old Documentation (POD) at the end of this Perl Script for further information
#
# SUBVERSION PROPERTIES
#
# $LastChangedDate$
# $Rev$
# $Author$
# $URL$
# $Id$


use strict;
use Carp;
use Pod::Usage;
# SOAP::Lite version 0.52 or newer is recommended by http://code.google.com/apis/soapsearch/api_faq.html#tech20
use SOAP::Lite 0.52;
use Getopt::Long;
use Data::Dumper;

my $VERSION = "0.7"; # May be required to upload script to CPAN i.e. http://www.cpan.org/scripts/submitting.html

# Supported Output Plug-Ins
my $tit_output_plugins = "TCP_FQDN_CSV, FQDN_CSV, NMAP_SH, NC_SH";

print "\n\"TCP Input Text\" Alpha v$VERSION\n";
print "\n";
print "Copyright 2008, 2009, 2010 Christian Heinrich\n";
print "Licensed under the Apache License, Version 2.0\n\n";
print "Output Plug-Ins: $tit_output_plugins\n\n";

# Command line meta-options
my $usage;
my $man; 
my $update;

# Command line arguments from the do_Google_Search SOAP Messages
my $google_api_key;
my $query;
my $site;
my $start;
my $gtos;

# The Google SOAP Search API .wsdl file
my $google_api_wsdl_file;

# TODO Display -usage if command line argument(s) are incorrect
GetOptions(
    "key=s"   => \$google_api_key,
    "wsdl=s"  => \$google_api_wsdl_file,
    "site=s"  => \$site, 
    "query=s" => \$query,
    "start=s" => \$start,
    "gtos"    => \$gtos,

    # Command line meta-options 
    # version is excluded as it is printed prior to processing the command line arguments
    # verbose is excluded as output is less then 25 lines
    "usage"   => \$usage,
    "man"     => \$man,  
    "update"  => \$update
);

if (($usage eq 1) or ($man eq 1)) {
    pod2usage(-verbose => 2);
    die();
}

if ($update eq 1) {
    print "Please execute \"svn update\" from the command line\n";
    die();
}

# For demonstrations without exposing the Google SOAP Search API insert your Google SOAP Search API Key below to use dic.pl -key "demo"
# TODO Merge into a configuration file
if ( $google_api_key == "demo" ) {
	# Replace "insert_google_api_key" with your Google SOAP Search API Key
  	# $google_api_key = "insert_google_api_key";
}

# Process the command line arguments

# Confirm the existence of the Google SOAP Search API WSDL file
if (!(-e $google_api_wsdl_file)) {
    die("WDSL File:$google_api_wsdl_file does not exist\n");
}

# -gtos is required
if ($gtos == "0") {
    die("-gtos not specified on the command line - You must acknowledge that you are violating Google's Terms of Service");
}

$start = $start - 1;
chomp($query);

# Subsitute -site for -query command line arguement
if ($query eq "") {
	# TODO Check $site has a value if $query doesn't
	$query = "site:" . "$site";
}

# strip ":" from Google Search Operator for Filename
# TODO Expand this to strip illegal filename chars i.e. \/:*?<>|
my $stripped_query = $query;
$stripped_query =~ s/://g;
my $dir = "$stripped_query/tit";

# The directory of the comma separated .csv files and shell scripts .sh of nmap and nc aka netcat
if ( !( -e $dir ) ) {
    print ("Creating ./$dir\n\n");
    if ( !( -e "./$stripped_query") ) {
        mkdir ("./$stripped_query");
    }
    mkdir ("$dir");
}
else { print "Appending ./$dir\n\n"; }

my $google_search_results
    = do_Google_Search( "$google_api_key", "$query", "$start" );

# TODO Display a warning if <estimatedTotalResultsCount> and <estimateIsExact> exceeds 1000

open( DATA_DUMPER, ">>./$dir/datadumper.txt" );
print DATA_DUMPER ( Data::Dumper::Dumper($google_search_results) );

open( TCP_FQDN_CSV, ">>./$dir/tit_tcp_fqdn.csv" );
open( FQDN_CSV, ">>./$dir/tit_fqdn.csv" );
open( NMAP_SH,      ">>./$dir/tit_nmap.sh" );
open( NC_SH, ">>./$dir/tit_nc.sh" );

# Loop through the results.
foreach
    my $google_search_result ( @{ $google_search_results->{resultElements} } )
{

    my $URL = $google_search_result->{URL};

    # Extract Protocol, Domain_Name, TCP_Port, $URI
    $URL =~ m|(\w+)://([^/:]+)(:\d+)?/(.*)|;
    my $protocol    = $1;
    my $domain_name = $2;
    my $URI         = ( "/" . $4 );
    my $TCP_port;

    # TODO $TCP_Port (i.e. $3) being uninitialized i.e. perl -w
    if   ( $3 =~ /:(\d+)/ ) { $TCP_port = $1 }
    else                    { $TCP_port = 80 }
    print "TCP/$TCP_port open at $domain_name\n";
    
    # TODO Consider creating a sub output_plug-in() if number of Output Plug-Ins expands
    print TCP_FQDN_CSV ("$domain_name,$TCP_port\n");
    print FQDN_CSV     ("$domain_name\n");
    print NMAP_SH      ("nmap -PN -sS -p T:$TCP_port $domain_name\n");
    print NC_SH        ("nc -vz $domain_name $TCP_port\n");
}

close TCP_FQDN_CSV;
close FQDN_CSV;
close NMAP_SH;
close NC_SH;

sub do_Google_Search {
	
    # Variable Naming Convention is as per Google SOAP Search API Reference Documentation
    my $key = $_[0];

    # $q is Google Search Query from Google SOAP Search API Reference
    # TODO Check length of Google Search Query is 2048 bytes
    # TODO Check Google Search Query is a maximum of 10 Words
    # TODO Check only one site: term is in the Google Search Query
    my $q = $_[1];

    # my $start = -start cmd line argument
    my $start = $_[2];

    # TODO Must add a test to ensure that $maxResults is between 1 to 1000
    my $maxResults = "10";

    # $filter is boolean i.e. either "true" or "false"
    my $filter = "false";

    # TODO Check Country of Restrict
    # TODO Check Topic of Restrict
    my $restricts  = "";
    my $safeSearch = "false";

    # TODO Check Language Restrict
    my $lr = "";

    # ie is Input Encoding and this has been deprecated in the Google SOAP Search API
    my $ie = "UTF-8";

    # oe is Output Encoding and this has been deprecated in the Google SOAP Search API
    my $oe = "UTF-8";

    # Location of the GoogleSearch WSDL file
    my $google_wsdl = "file:$google_api_wsdl_file";

    # Create a new SOAP::Lite instance, feeding it GoogleSearch.wsdl
    my $google_search         = SOAP::Lite->service("$google_wsdl");
    # TODO Confirm that connection with api.google.com can be established
    my $google_search_results = $google_search->doGoogleSearch(
        $key,       $q,          $start, $maxResults, $filter,
        $restricts, $safeSearch, $lr,    $ie,         $oe
    );
    # TODO Confirm that doGoogleSearchResponse SOAP Message is not empty due to exceeding 10K SOAP Messages with Google SOAP Search API Key 
    return $google_search_results;
}


=head1 NAME

tit.pl - "TCP Input Text"

=head1 VERSION

This documentation refers to tit Alpha v0.7 

WARNING: You are violating Google's Terms of Service if you execute this post
http://googlecode.blogspot.com/2009/08/well-earned-retirement-for-soap-search.html

=head1 USAGE

tit.pl -key [key] -query [Google Search Query] -start [Starting Google Search Result Number] -wsdl [Path for GoogleSearch.wsdl] -gtos

=head1 REQUIRED ARGUEMENTS

 -key		Google SOAP Search API Key
 -wsdl    	Google SOAP Search API WSDL file i.e. GoogleSearch.wsdl 
 -q         Google Search Query
 -site      Alternate Google Search Query i.e. inserts site: Google Advanced Search Operator
 -start		Starting Google Search Result Number
 -gtos      Acknowledgement of violation of Google's Terms of Service
 				
=head1 OPTIONAL ARGUEMENTS

 -man		Displays POD and exits.
 -usage		Displays POD and exits.
 -update	Displays the svn command to retrieve the latest update from code.google.com

=head1 DESCRIPTION

"TCP Input Text" implements the Google SOAP Search API to extract TCP Ports and Fully Qualified Domain Names (FQDN) from Google Search Results into a .csv file and individual shell scripts for nmap and nc aka netcat to provide assurance of a listening TCP service since the time that has past of the last crawl performed by the "GoogleBot".

=head1 DEPENDENCIES

=head1 PREREQUISITES

SOAP::Lite v0.52 CPAN Module
Data::Dumper CPAN Module

=head1 COREQUISITES

=head1 OSNAMES

cygwin

=head1 SCRIPT CATEGORIES

Web

=head1 INCOMPATIBILITIES

=head1 BUGS AND LIMITATIONS

Please refer to the comments beginning with "TODO" in the Perl Code.

=head1 AUTHOR

Christian Heinrich

=head1 CONTACT INFORMATION

cmlh@tcpinputtext.org
christian.heinrich@cmlh.id.au
cmlh@cpan.org

=head1 MAILING LIST

http://groups.google.com/group/tcp-input-text

=head1 REPOSITORY

http://code.google.com/p/tit

=head1 FURTHER INFORMATION AND UPDATES

http://tcpinputtext.org
http://del.icio.us/cmlh/tit

=head1 LICENSE AND COPYRIGHT

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. 

Copyright 2008, 2009, 2010 Christian Heinrich